/* node.h
* libxml++ and this file are copyright (C) 2000 by Ari Johnson, and
* are covered by the GNU Lesser General Public License, which should be
* included with libxml++ as the file COPYING.
*/

#ifndef __LIBXMLPP_NODES_NODE_H
#define __LIBXMLPP_NODES_NODE_H

#include "../noncopyable.h"
#include "../exceptions/exception.h"
#include <glibmm/ustring.h>
#include <list>
#include <map>
#include <vector>

#ifndef DOXYGEN_SHOULD_SKIP_THIS
extern "C"
{
  struct _xmlNode;
}
#endif //DOXYGEN_SHOULD_SKIP_THIS

namespace Xml
{

  class TextNode;
  class Element;
  class Attribute;
  class Document;

  class Node;
  typedef std::vector<Node*> NodeSet;
  typedef std::vector<Node*> NodeList;

  enum NodeType
  {
    XML_ELEMENT_NODE=		1,
    XML_ATTRIBUTE_NODE=		2,
    XML_TEXT_NODE=		3,
    XML_CDATA_SECTION_NODE=	4,
    XML_ENTITY_REF_NODE=	5,
    XML_ENTITY_NODE=		6,
    XML_PI_NODE=		7,
    XML_COMMENT_NODE=		8,
    XML_DOCUMENT_NODE=		9,
    XML_DOCUMENT_TYPE_NODE=	10,
    XML_DOCUMENT_FRAG_NODE=	11,
    XML_NOTATION_NODE=		12,
    XML_HTML_DOCUMENT_NODE=	13,
    XML_DTD_NODE=		14,
    XML_ELEMENT_DECL=		15,
    XML_ATTRIBUTE_DECL=		16,
    XML_ENTITY_DECL=		17,
    XML_NAMESPACE_DECL=		18,
    XML_XINCLUDE_START=		19,
    XML_XINCLUDE_END=		20
#ifdef LIBXML_DOCB_ENABLED
   ,XML_DOCB_DOCUMENT_NODE=	21
#endif
};

  /** Represents XML Nodes.
  * You should never new or delete Nodes. The Parser will create and manage them for you.
  */
  class Node : public NonCopyable
  {
  public:
    explicit Node(_xmlNode* node);
    virtual ~Node();

    /** Get the name of this node.
    * @returns The node's name.
    */
    Glib::ustring get_name() const;

    /** Set the name of this node.
    * @param name The new name for the node.
    */
    void set_name(const Glib::ustring& name);

    /** Set the namespace prefix used by the node.
    * If no such namespace prefix has been declared then this method will throw an exception.
    * @param ns_prefix The namespace prefix.
    */
    void set_namespace(const Glib::ustring& ns_prefix);

    Glib::ustring get_namespace_prefix() const;
    Glib::ustring get_namespace_uri() const;

    /** Discover at what line number this node occurs in the XML file.
    * @returns The line number.
    */
    int get_line() const;

    /** Get the parent element for this node.
    * @returns The parent node
    */
    const Element* get_parent() const;  

    /** Get the parent element for this node.
    * @returns The parent node
    */
    Element* get_parent();  

    /** Get the next sibling for this node.
    * @returns The next sibling
    */
    const Node* get_next_sibling() const;  

    /** Get the next sibling for this node.
    * @returns The next sibling
    */
    Node* get_next_sibling();  

    /** Get the previous sibling for this node .
    * @returns The previous sibling
    */
    const Node* get_previous_sibling() const;  

    /** Get the previous sibling for this node.
    * @returns The previous sibling
    */
    Node* get_previous_sibling();  

    /** Obtain the list of child nodes. You may optionally obtain a list of only the child nodes which have a certain name.
    * @param name The names of the child nodes to get. If you do not specigy a name, then the list will contain all nodes, regardless of their names.
    * @returns The list of child nodes.
    */
    NodeList get_children(const Glib::ustring& name = Glib::ustring());

    /** Obtain the list of child nodes. You may optionally obtain a list of only the child nodes which have a certain name.
    * @param name The names of the child nodes to get. If you do not specigy a name, then the list will contain all nodes, regardless of their names.
    * @returns The list of child nodes.
    */
    const NodeList get_children(const Glib::ustring& name = Glib::ustring()) const;

    /** Add a child element to this node.
    * @param name The new node name
    * @param ns_prefix The namespace prefix. If the prefix has not been declared then this method will throw an exception.
    * @returns The newly-created element
    */
    Element* add_child(const Glib::ustring& name,
      const Glib::ustring& ns_prefix = Glib::ustring());

    /** Add a child element to this node after the specified existing child node.
    *
    * @newin2p24
    *
    * @param previous_sibling An existing child node.
    * @param name The new node name
    * @param ns_prefix The namespace prefix. If the prefix has not been declared then this method will throw an exception.
    * @returns The newly-created element
    */
    Element* add_child(Node* previous_sibling, const Glib::ustring& name,
      const Glib::ustring& ns_prefix = Glib::ustring());

    /** Add a child element to this node before the specified existing child node.
    *
    * @newin2p24
    *
    * @param next_sibling An existing child node.
    * @param name The new node name
    * @param ns_prefix The namespace prefix. If the prefix has not been declared then this method will throw an exception.
    * @returns The newly-created element
    */
    Element* add_child_before(Node* next_sibling, const Glib::ustring& name,
      const Glib::ustring& ns_prefix = Glib::ustring());

    /** Remove the child node.
    * @param node The child node to remove. This Node will be deleted and therefore unusable after calling this method.
    */
    void remove_child(Node* node);

    /** Import node(s) from another document under this node, without affecting the source node.
    * @param node The node to copy and insert under the current node.
    * @param recursive Whether to import the child nodes also. Defaults to true.
    * @returns The newly-created node.
    */
    Node* import_node(const Node* node, bool recursive = true);


    /** Return the XPath of this node.
    * @result The XPath of the node.
    */
    Glib::ustring get_path() const;

    /** Find nodes from a XPath expression.
    * @param xpath The XPath of the nodes.
    */
    NodeSet find(const Glib::ustring& xpath) const;

    /** A map of namespace prefixes to namespace URIs.
    */
    typedef std::map<Glib::ustring, Glib::ustring> PrefixNsMap;

    /** Find nodes from a XPath expression.
    * @param xpath The XPath of the nodes.
    * @param namespaces A map of namespace prefixes to namespace URIs to be used while finding.
    */
    NodeSet find(const Glib::ustring& xpath, const PrefixNsMap& namespaces) const;


    ///Access the underlying libxml implementation.
    _xmlNode* cobj();

    ///Access the underlying libxml implementation.
    const _xmlNode* cobj() const;

    Document* get_document();
    const Document* get_document() const;

    NodeType get_node_type() const;

  protected:

    ///Create the C instance ready to be added to the parent node.
    _xmlNode* create_new_child_node(const Glib::ustring& name, const Glib::ustring& ns_prefix);

  private:
    _xmlNode* impl_;
  };

} // namespace Xml

#endif //__LIBXMLPP_NODES_NODE_H
